home *** CD-ROM | disk | FTP | other *** search
/ EnigmA Amiga Run 1995 November / EnigmA AMIGA RUN 02 (1995)(G.R. Edizioni)(IT)[!][issue 1995-11][Skylink CD].iso / earcd / util / text / frexxedv.lha / FrexxEdpatch / fpl / wordpro.FPL < prev    next >
Text File  |  1995-09-22  |  15KB  |  484 lines

  1. /*
  2.  * WHAT IS THIS?
  3.  *
  4.  * WordPro.FPL is perhaps the most advanced FPL program written for FrexxEd
  5.  * at this time. It brings interactive word-processor-style word wrap
  6.  * functionality to the editor.
  7.  *
  8.  * "word-processor-style" means that
  9.  * A. All word wrapping is "paragraph" oriented. All lines within the same
  10.  *    paragraph are separated with 'soft' newlines (that is a "\x01\n" in my
  11.  *    program!),
  12.  * B. If a line is longer than the right margin is set to, the words that are
  13.  *    "off the edge" are moved down to the line below and a 'soft' newline is
  14.  *    added to the end of the line. If the line below gets too long by the
  15.  *    operation, it performs the same with that line...
  16.  * C. If the first word of the line below would fit at the end of the current,
  17.  *    it is moved up. (And then the same check is done on the line below.)
  18.  */
  19.  
  20. /*
  21.  * Current restrictions:
  22.  *  o Pretty slow on large paragraphs, perhaps I'll make a limit in amount
  23.  *    of lines that can get 'fixed' on each invoke.
  24.  *  o If the first word of a line fits on the line above is only checked for
  25.  *    if the current line is out of right margin ( and '_fitprev' is on ).
  26.  *  o If the first word of the line below fits on the current line is only
  27.  *    checked for when deleting.
  28.  *  o There is no kind of left margin indentation support
  29.  */
  30.  
  31. /*
  32.  * WordProWrap()
  33.  *
  34.  * Checks the current line to see if it is longer than the margin allows.
  35.  * If it is, it performs actions to word wrap it properly
  36.  */
  37. export int WordProWrap(void)
  38. {
  39.   string word;
  40.   int sbyte = ReadInfo("byte_position");
  41.   int line = ReadInfo("line");
  42.   int sline=line;
  43.   int cursorline = line;
  44.   int jumpback;
  45.   int wrapped;
  46.   int len = ReadInfo("line_length");
  47.   int visible = Visible(0);
  48.   const int wall = ReadInfo("wall_right");
  49.   if(wall >= len)
  50.     return 1;
  51.   SetInfo(-1, "_wordpro", ReadInfo("_wordpro")+1);
  52.   do {
  53.     int steps;
  54.     int backsteps;
  55.     len = ReadInfo("line_length");
  56.     if(IsLineWordWrapped(line)) {
  57.       wrapped=1; /* it is wrapped! */
  58.       len--; /* don't count the cookie! */
  59.     }
  60.     else
  61.       wrapped=0;
  62.  
  63.     if(wall >= len)
  64.       break;
  65.  
  66.     // Request(sprintf("line %d is %d bytes long", line, len));
  67.     jumpback=1;
  68.     if(line == cursorline) {
  69.       /* the cursor-line */
  70.       if(ReadInfo("column") + (len-sbyte) >= wall) {
  71.         /* we reached the edge when appending text to the left side
  72.            of text that is about to get wrapped! */
  73.         backsteps= len-sbyte;  /* this number of steps from the current
  74.                         right edge */
  75.         jumpback=0;
  76.       }
  77.  
  78.       if(ReadInfo("WordPro_fitprev")) {
  79.         /*
  80.          * This checks if the first word on the line fits on the uppper line
  81.          */
  82.         while (IsLineWordWrapped(line-1)) {
  83.           int uplen;
  84.           GotoLine(line-1);
  85.           uplen = ReadInfo("line_length");
  86.           word = GetWord(line, 0);
  87.           if(sbyte > strlen(word) &&
  88.              uplen + strlen(word)+2 < wall) {
  89.             GotoLine(--line, len);
  90.             Backspace();
  91.             Delete();
  92.             Output(" ");
  93.             sbyte += uplen;
  94.             sline--;
  95.             //Request("We merged the line with the upper one!");
  96.           }
  97.           else {
  98.             GotoLine(line);
  99.             break;
  100.           }
  101.         }
  102.       }
  103.       /* ----- */
  104.       cursorline=-1; /* never ever do this again */
  105.       
  106.     }
  107.  
  108.     GotoLine(line, ReadInfo("line_length")); /* jump to end of line! */
  109.     do {
  110.       steps+=CursorLeftWord();
  111.     } while (line==ReadInfo("line") &&
  112.              ReadInfo("column")>1 &&
  113.              wall<ReadInfo("column"));
  114.  
  115.     if(!jumpback && (steps < backsteps)) {
  116.       /* then this is a false backstepper! */
  117.       jumpback=1;
  118.     }
  119.  
  120.     if (line==ReadInfo("line") && ReadInfo("column")>1) {
  121.       int byte = ReadInfo("byte_position");
  122.       while(GetChar(--byte) != ' ') {
  123.          steps++;
  124.          CursorLeft();
  125.          if(!byte) {
  126.             GotoLine(line,wall);
  127.             Output("\x01\n");
  128.             break 2;
  129.          }
  130.       }
  131.       byte++;
  132.       while(GetChar(--byte) == ' ')
  133.         Backspace();
  134.       Output("\x01\n");
  135.     }
  136.     /*
  137.     if(wall <= ReadInfo("column")) {
  138.       Output("\x01\n");
  139.     }
  140.     */
  141.     line++; /* we've come down one line by now! */
  142.     if(!jumpback) {
  143.       jumpback=1;
  144.       sbyte = steps-backsteps;
  145.       sline = line;
  146.     }
  147.     if(wrapped) {
  148.       //Request("This is a wrapped line, check if next word fits here!");
  149.       len = ReadInfo("line_length");
  150.       word = GetWord(line+1, 0); /* get first word on next line */
  151.       if(strlen(word)+len < wall) {
  152.         /* we think next word is gonna fit on our line! */
  153.         GotoLine(line, len); /* jump to end of line! */
  154.         Backspace(); /* get rid of our 0x01 code! */
  155.         Delete(); /* Merge next line to our! */
  156.         if(GetChar()!=' ')
  157.           Output(" "); /* make us a space! */
  158.       }
  159.       else {
  160.         //Request("Nope! It doesn't...");
  161.         if(len < wall)
  162.           wrapped=0;
  163.       }
  164.     }
  165.     else {
  166.       //Request(sprintf("line %d lines %d", line, ReadInfo("lines")));
  167.       if(line < ReadInfo("lines") && !IsLineWordWrapped(line)) {
  168.         //Request("boo");
  169.         sbyte++;
  170.       }
  171.     }
  172.   } while(wrapped); /* continue until done! */
  173.   if(jumpback) {
  174.     GotoLine(sline, sbyte); /* jump to start-pos! */
  175.     if(GetCursor(sbyte, sline) < sbyte) {
  176.       GotoLine(sline+1);
  177.     }
  178.   }
  179.   SetInfo(-1, "_wordpro", ReadInfo("_wordpro")-1);
  180.   Visible(visible);
  181. }
  182.  
  183. /*
  184.  * WordProDelete0x01()
  185.  *
  186.  * Called before each invoke of Delete() to make a deletion of the 'soft'
  187.  * newline character (ASCII 0x01) make a deletion of the following
  188.  * newline too, and a decent word wrap if the line gets too long!
  189.  */
  190. int newlinedelete;
  191. export int WordProDelete0x01(int number)
  192. {
  193.   if(1 == GetChar()) { /* are we standing on a 0x01 character? */
  194.     SetInfo(-1, "_wordpro", ReadInfo("_wordpro")+1);
  195.     if(number>1) /* specified number? */
  196.       number--;
  197.     Delete(number+2); /* delete the 0x01 and newline too then! */
  198.     WordProWrap(); /* wrap this long line! */
  199.     SetInfo(-1, "_wordpro", ReadInfo("_wordpro")-1);
  200.     return 1; /* quit the actual Delete() */
  201.   }
  202. }
  203.  
  204. /*
  205.  * WordProDelete0x01()
  206.  *
  207.  * Called after each invoke of Delete() to make a decent word wrap if the
  208.  * line gets short enough to fit the first word on the line below!
  209.  */
  210. export int WordProDelete(void)
  211. {
  212.   int line=ReadInfo("line");
  213.   if(IsLineWordWrapped(line)) {
  214.     int len;
  215.     int sline=line;
  216.     int sbyte=ReadInfo("byte_position");
  217.     int visible=Visible(0);
  218.     string word;
  219.     SetInfo(-1, "_wordpro", ReadInfo("_wordpro")+1);
  220.     while(line <= ReadInfo("lines")) {
  221.       word = GetWord(line+1, 0); /* get first word on next line */
  222.       len = ReadInfo("line_length") + strlen(word)+1; /* a space too! */
  223.       if(ReadInfo("wall_right") >= len) {
  224.         GotoLine(line++, len);
  225.         Backspace(); /* remove magic cookie! */
  226.         Delete(); /* remove newline */
  227.         Output(" ");
  228.         WordProWrap(); /* do the dance! */
  229.       }
  230.       else
  231.         break;
  232.     }
  233.     GotoLine(sline, sbyte); /* jump to start-pos! */      
  234.     SetInfo(-1, "_wordpro", ReadInfo("_wordpro")-1);
  235.     Visible(visible);
  236.   }  
  237. }
  238.  
  239. /*
  240.  * WordProSave()
  241.  *
  242.  * Called before the actual save is done. If the user confirms the question,
  243.  * it replaces all soft newlines to spaces and then saves it like that.
  244.  */
  245. int oursavehook;
  246. export int WordProSave(string file, string pack)
  247. {
  248.   int new;
  249.   int savemode = ReadInfo("wordpro_save");
  250.   if(3 == savemode) {
  251.     savemode = Request("How do you want it saved?", "Save option",
  252.                        "Raw|Softs too|Only hards|Cancel");
  253.     if(!savemode--) {
  254.       return 1;
  255.     }
  256.   }
  257.   if(!oursavehook && savemode) {
  258.     int us = GetEntryID();
  259.     new = New();
  260.     oursavehook=1; /* prevent us from getting recursive! */
  261.     if(new) {
  262.       string filename;
  263.       string replacedsoft;
  264.       CurrentBuffer(new); /* jump to the new one */
  265.       BlockPaste(us); /* paste the original buffer in the new */
  266.       GotoLine(1); /* go to the top! */
  267.  
  268.       if(savemode==2) {
  269.         /* this is "only hard" newlines should be left, replace all softies
  270.            with a single space! */
  271.         replacedsoft = " ";
  272.       }
  273.       else {
  274.         /* Keep the soft newlines as newlines in the output! */
  275.         replacedsoft = "\n";
  276.       }
  277.       Replace(1, "\x01\n", replacedsoft, "f+"); /* replace all soft newlines */
  278.       
  279.       filename = ReadInfo("full_file_name", us); /* get file name */
  280.       if(strlen(file))
  281.         /* done like this to still support Save() with a given name */
  282.         filename=file;
  283.       Save(filename, pack); /* save the new buffer to the original file */
  284.       CurrentBuffer(us); /* jump back to the orignal buffer */
  285.  
  286.       /*
  287.        * Now, write the date and time of our "faked" save into the
  288.        * info variable for our good old buffer to maintain the proper
  289.        * data! (and most of all, to avoid that nasty 'FileChanged'
  290.        * exception when trying to save a file that is older than the file
  291.        * actually is on disk!)
  292.        */
  293.       SetInfo(us, "ds_Days", ReadInfo("ds_Days", new));
  294.       SetInfo(us, "ds_Minute", ReadInfo("ds_Minute", new));
  295.       SetInfo(us, "ds_Tick", ReadInfo("ds_Tick", new));
  296.  
  297.       SetInfo(us, "changes", 0); /* clear the changes flag! */
  298.       Kill(new); /* kill our temporary buffer */
  299.     }
  300.     oursavehook=0; /* allow us to get started once again! */
  301.   }
  302.   return new; /* if non-zero, the "real" save is stopped */
  303. }
  304.  
  305. /*
  306.  * WordProOpenAndWrap()
  307.  *
  308.  * This function takes the specified file, or if none is specified, prompts
  309.  * for one, loads it into a new buffer and word wraps it according to
  310.  * its knowledge.
  311.  */
  312. int export WordProOpenAndWrap(string file)
  313. {
  314.   int new;
  315.   if(!strlen(file)) {
  316.     file=PromptFile();
  317.     if(!strlen(file))
  318.       /* cancel or error occured! */
  319.       return 1;
  320.   }
  321.   new = New();
  322.   if(new) {
  323.     SetInfo(-1, "_wordpro", ReadInfo("_wordpro")+1); /* prevent recurse */
  324.     CurrentBuffer(new); /* jump to new buffer */
  325.     Load(file); /* load the specified file */
  326.     WordProWrapLines(1, ReadInfo("lines")); /* do the entire buffer! */
  327.     SetInfo(-1, "_wordpro", ReadInfo("_wordpro")-1); /* allow recurse */
  328.     SetInfo(-1, "wordpro", 1); /* 'wordpro' is enabled for this buffer! */
  329.   }
  330.   else
  331.     return 1;
  332. }
  333.  
  334. int export WordProWrapBuffer()
  335. {
  336.   SetInfo(-1, "_wordpro", ReadInfo("_wordpro")+1); /* prevent recurse */
  337.   WordProWrapLines(1, ReadInfo("lines")); /* do the entire buffer! */
  338.   SetInfo(-1, "_wordpro", ReadInfo("_wordpro")-1); /* allow recurse */
  339. }
  340.  
  341. int export WordProWrapBlock()
  342. {
  343.   if(ReadInfo("block_exist")) {
  344.     BlockMark(0);
  345.     WordProWrapLines(ReadInfo("block_begin_y"), ReadInfo("block_end_y"));
  346.   }
  347.   else
  348.     ReturnStatus("No block marked!");
  349. }
  350.  
  351. int export WordProWrapLines(int firstline, int lastline)
  352. {
  353.   int line;
  354.   int numlines;
  355.   int len;
  356.   int count;
  357.  
  358.   SetInfo(-1, "wordpro", 1); /* we wanna run wordpro dammit! ;) */
  359.  
  360.   /* Do the tango!
  361.    *
  362.    * Combine all 'paragraphs' with soft newlines!
  363.    */
  364.   numlines = ReadInfo("lines"); /* read number of lines */
  365.   for(line= firstline; line < lastline; line++) { /* the last line can't be soft! */
  366.     len = GetByte(999999, line); /* get byte position */
  367.     if(len > ReadInfo("wall_right")/2 &&
  368.        !IsLineWordWrapped(line)) {
  369.       /* the text of this line reaches longer than half the width */
  370.       /* and it isn't previously wrapped (like if the file was saved 'raw'
  371.          in a previous WordPro editing session)! */
  372.       GotoLine(line, len); /* goto end of line */
  373.  
  374.       /* The expression just above does not fully function in FrexxEd 1.7
  375.          and earlier if the length of the line is longer than the width
  376.          of the screen/window... */
  377.       
  378.       if(!Isspace(GetChar(0, line+1))) {
  379.         /* The paragraph seems to continue on the following line,
  380.            since the first column of that line isn't white space! */
  381.         Output("\x01");
  382.       }
  383.     }
  384.     /* next one please! */
  385.   }
  386.   /*
  387.    * Now, let's scan all lines and wrap them to a decent level!
  388.    */
  389.   for(line= firstline; line <= lastline;) {
  390.     GotoLine(line); /* jump to the line in question! */
  391.     WordProWrap(); /* do the secret wrap trick! */
  392.     count = ReadInfo("lines")-numlines; /* this amount of new lines! */
  393.     numlines += count; /* we're at this amount now! */
  394.     lastline += count; /* add to this one too! */
  395.     if(count)
  396.       line += count; /* skip those new ones since they're already wrapped! */
  397.     else
  398.       line++;
  399.   }
  400.   SetInfo(-1, "_wordpro", ReadInfo("_wordpro")-1); /* allow yet again! */
  401. }
  402.  
  403. export void WordProPrefs()
  404. {
  405.   PromptInfo(-1, "WordPro Preferences", -1, -1,
  406.              "wordpro", "wall_right", "wordpro_save", "wordpro_fitprev",
  407.              "wordpro_open");
  408. }
  409.  
  410. int IsLineWordWrapped(int line)
  411. {
  412.   if(line>0) {
  413.     int len= GetByte(999999, line);
  414.     if(len>1 && (1 == GetChar(len-1, line))) {
  415.       return 1;
  416.     }
  417.   }
  418.   return 0;
  419. }
  420.  
  421. ReadInfo("_wordpro");
  422. if(GetErrNo()) { /* just a way to make the menu only once, even if this file
  423.                     is executed repeatedly! */
  424.   /*
  425.    * Create our menu setup:
  426.    */
  427.   MenuAdd("t", "WordPro");
  428.     MenuAdd("i", "Open...", "WordProOpenAndWrap(\"\");", "control w o");
  429.     MenuAdd("i", "Wrap Block", "WordProWrapBlock();", "control w b");
  430.     MenuAdd("i", "Save...", "Save();", "control w s");
  431.     MenuAdd("i", "Prefs", "WordProPrefs();");
  432.   
  433.   MenuBuild();
  434. }
  435. /*
  436.  * This little beast is here only to prevent recursion where we don't want
  437.  * it...
  438.  */
  439. ConstructInfo("_wordpro", "", "", "ILH", "", 0, 999, 0);
  440.  
  441. /*
  442.  * This is the general right-edge setting.
  443.  */
  444. ConstructInfo("wall_right", "", "", "WIL(display)", "", 0, 999, 79);
  445.  
  446. /*
  447.  * Toggle this mode on/off with this!
  448.  */
  449. ConstructInfo("wordpro", "", "", "WBL(system)", "", 0, 0);
  450.  
  451. /*
  452.  * Control how the saving is performed with this.
  453.  */
  454. ConstructInfo("wordpro_save", "", "", "WCG(system)", "Raw|Softs too|Only Hards|Query", 0, 0, 2);
  455.  
  456. /*
  457.  * Make all the regular loads word wrap the file!
  458.  */
  459. ConstructInfo("wordpro_open", "", "", "WBG(system)", "", 0, 0, 0);
  460.  
  461. /*
  462.  * This variable enables the wordpro script to check if the first word of
  463.  * the line fits on the line above.
  464.  */
  465. ConstructInfo("wordpro_fitprev", "", "", "WBG(system)", "", 0, 0, 1);
  466.  
  467. FACT(0x01, 'S', "^", ' '); /* non-visible character! */
  468.  
  469. AddMode(0,"wordpro", "","");                // Add as minor mode!
  470.  
  471. /*
  472.  * All this can only be accomplished by some pretty extensive hooking...
  473.  */
  474.  
  475. HookPast("Output", "WordProWrap();", "wordpro&!_wordpro");
  476. HookPast("BlockPaste", "WordProWrap();", "wordpro&!_wordpro");
  477. HookPast("Delete", "WordProDelete();", "wordpro&!_wordpro");
  478. HookPast("Backspace", "WordProDelete();", "wordpro&!_wordpro");
  479. HookPast("DeleteWord", "WordProDelete();", "wordpro&!_wordpro");
  480. HookPast("BackspaceWord", "WordProDelete();", "wordpro&!_wordpro");
  481. Hook("Save", "WordProSave", "wordpro");
  482. Hook("Delete", "WordProDelete0x01", "wordpro&!_wordpro");
  483. Hook("GotFile", "WordProWrapBuffer();", "wordpro_open&!_wordpro");
  484.